package com.crazyteam.genid.util;

import org.apache.commons.lang.time.FastDateFormat;

import java.util.Date;


public class PrimaryUtils {

	/**校验位的权重，由10个数字组成，超过需求循环使用*/
	private static final int[] WEIGHT={7,9,10,5,8,4,2,1,6,3};    
	/**校验位的校验码，由10个数字组成,超过需求循环使用*/
	private static final char[] VALIDATE={ '1','0','5','9','8','7','6','4','3','2'};   
	
	/**seq对应的随机自增的 8位数*/
	private static final int NUM = 8;
	
	/**除数：用于内部校验码生成*/
	private static final int MOD = 10;

	/** 日期格式, 流水号前缀 */
	private static final FastDateFormat fullfdf = FastDateFormat.getInstance("yyyyMMdd");
	
	/** 日期格式, 流水号前缀 */
	private static final FastDateFormat fdf = FastDateFormat.getInstance("yyMMdd");

	/** 日期格式, 流水号前缀 */
	private static final FastDateFormat ymfdf = FastDateFormat.getInstance("yyMM");

	/** 日期格式, 流水号前缀 */
	private static final FastDateFormat yyfdf = FastDateFormat.getInstance("yy");
	
	/**
	 * 获取主键 
	 * @param primaryKey 
	 * @return 序列主键  yyMMdd+ 8位自增 +1位校验码
	 */
	public static String genId(String primaryKey){
		// 获取增长序列
		long seq = GenPrimaryKeyFactory.nextPrimaryKey(primaryKey);
		
		// 获取日期前缀
		String date = fdf.format(new Date());
		
		// 拼接流水编号
		char[] seqChars = CharUtils.charsAdd(date.toCharArray(), 
				CharUtils.longTochars(seq, new char[NUM]));
		
		char charValidate = getValidateCode(seqChars);
		// 拼接出数据库保存的订单ID
		char[] seqValiChars = CharUtils.charsAdd(seqChars, charValidate);

		return CharUtils.charsToString(seqValiChars);
	}
	
	/**
	 * 获取主键
	 * @param primaryKey
	 * @param step 随机步长(在step随机增长)
	 * @return 序列主键  yyMMdd+ 8位自增 +1位校验码
	 */
	public static String genId(String primaryKey, int step){
		// 获取步长除数
		// 获取步长
		int inc = (int) (System.currentTimeMillis() % step + 1);
		// 获取增长序列
		long seq = GenPrimaryKeyFactory.nextPrimaryKey(primaryKey, inc);
		
		// 获取日期前缀
		String date = fdf.format(new Date());
		
		// 拼接流水编号
		char[] seqChars = CharUtils.charsAdd(date.toCharArray(), 
				CharUtils.longTochars(seq, new char[NUM]));
		
		char charValidate = getValidateCode(seqChars);
		// 拼接出数据库保存的订单ID
		char[] seqValiChars = CharUtils.charsAdd(seqChars, charValidate);
		return CharUtils.charsToString(seqValiChars);
	}

	/**
	 * 获取主键
	 * @param primaryKey
	 * @return 序列主键  8位自增 +1位校验码
	 */
	public static String nextIncrement(String primaryKey, int length){
		// 获取增长序列
		long seq = GenPrimaryKeyFactory.nextPrimaryKey(primaryKey);


		// 拼接流水编号
		char[] seqChars = CharUtils.longTochars(seq, new char[length]);

		char charValidate = getValidateCode(seqChars);
		// 拼接出数据库保存的订单ID
		char[] seqValiChars = CharUtils.charsAdd(seqChars, charValidate);

		return CharUtils.charsToString(seqValiChars);
	}

	/**
	 * 获取主键
	 * @param primaryKey
	 * @return 序列主键  8位自增 +1位校验码
	 */
	public static String nextIncrementWithStep(String primaryKey, int length,int step){
		int inc = (int) (System.currentTimeMillis() % step + 1);
		// 获取增长序列
		long seq = GenPrimaryKeyFactory.nextPrimaryKey(primaryKey,inc);

		// 拼接流水编号
		char[] seqChars = CharUtils.longTochars(seq, new char[length]);

		char charValidate = getValidateCode(seqChars);
		// 拼接出数据库保存的订单ID
		char[] seqValiChars = CharUtils.charsAdd(seqChars, charValidate);

		return CharUtils.charsToString(seqValiChars);
	}

	/**
	 * 获取主键
	 * @param primaryKey
	 * @return 序列主键  8位自增 +1位校验码
	 */
	public static String nextIncrement(String primaryKey){
		return nextIncrement(primaryKey, NUM);
	}

	/**
	 * 自定义规则生成主键
	 * @param primaryKey 主键唯一标识
	 * @param timePrefixNum 时间戳位数 只支持0,2,4,6
	 * @param length 随机系列号位数
	 * @param step 增长随机步长
	 * @param needCheck 是否需要校验位
	 * @return
	 */
	public static String genIdByRule(String primaryKey,int timePrefixNum,int length,int step,boolean needCheck){
		if( 2!=timePrefixNum &&  4!=timePrefixNum && 6!=timePrefixNum && 8!=timePrefixNum){
			return nextIncrementWithStep(primaryKey,length,step);
		}
		if(timePrefixNum==0){
			return nextIncrementWithStep(primaryKey,length,step);
		}
		// 获取步长除数
		// 获取步长
		int inc = (int) (System.currentTimeMillis() % step + 1);
		// 获取增长序列
		long seq = GenPrimaryKeyFactory.nextPrimaryKey(primaryKey, inc);
		String date ;
		if(timePrefixNum==2){
			date = yyfdf.format(new Date());
		}else if(timePrefixNum==4){
			date = ymfdf.format(new Date());
		}else if(timePrefixNum==6){
			date = fdf.format(new Date());
		}else{
			date = fullfdf.format(new Date());
		}

		// 拼接流水编号
		char[] seqChars = CharUtils.charsAdd(date.toCharArray(),
				CharUtils.longTochars(seq, new char[length]));
		if(!needCheck){
			return CharUtils.charsToString(seqChars);
		}
		char charValidate = getValidateCode(seqChars);
		// 拼接出数据库保存的订单ID
		char[] seqValiChars = CharUtils.charsAdd(seqChars, charValidate);
		return CharUtils.charsToString(seqValiChars);
	}

	/**
	 * 获取内部校验码，以char的形式返回
	 * @param seqChars 
	 * @return char 校验码 （数字型字符）
	 */
	public static char getValidateCode(char seqChars[]) {
		int sum = 0;
		for (int i = 0; i < seqChars.length; i++) {
			sum = sum + Integer.parseInt(String.valueOf(seqChars[i]))
					* WEIGHT[i % MOD];
		}
		return VALIDATE[sum % MOD];
	}
}
